/**
 * 2个数字的加法
 * @param num1 数值
 * @param num2 数值
 * @returns {string} 2个数值加法的结果
 */
function numberAdd(num1, num2) {
    if (num1 == "" || num2 == "") {
        throw new TypeError("参数非法");
    }
    // 判断是否异号
    var num1Str = num1.toString();
    var num2Str = num2.toString();
    var num1Flag = isPositiveNum(num1Str);
    var num2Flag = isPositiveNum(num2Str);
    var num1Obj = new NumberObject(num1Str);
    var num2Obj = new NumberObject(num2Str);
    if (num1Flag ^ num2Flag) {
        // 2个数字 符号不相等
        return num1Obj.subtract(num2Obj);
    } else {
        // 2个数字 符号相等
        return num1Obj.add(num2Obj);

    }
    return "";
}

/**
 * 左对齐，从 第 startIndex 开始进行正整数加法运算，startIndex 之后的数值直接追加到末尾
 * @param str1 待加数
 * @param str2 待加数
 * @param startIndex 第几位是个位
 * @returns {string}
 */
function positiveStrAddInLeftAlign(str1, str2, startIndex) {
    let needAdd = 0;
    let newStr = '';
    for (let i = startIndex; i >= 0; i--) {
        let num1 = Number.parseInt(str1.charAt(i));
        let num2 = Number.parseInt(str2.charAt(i));
        let sum = num1 + num2 + needAdd;
        newStr = (sum % 10) + newStr;
        if (sum >= 10) {
            needAdd = 1;
        } else {
            needAdd = 0;
        }
    }
    if (needAdd == 1) {
        newStr = '1' + newStr;
    }
    let subStrStartIndex = startIndex + 1;
    if (str1.length > subStrStartIndex) {
        newStr = newStr + str1.substr(subStrStartIndex);
    } else if (str2.length > subStrStartIndex) {
        newStr = newStr + str2.substr(subStrStartIndex);
    }
    return newStr;
}

/**
 * 清除0前缀
 * @param {string} numStr 数字字符
 * @returns {string}
 */
function clearZeroPrefix(numStr) {
    let i = 0;
    for (; i < numStr.length; i++) {
        let numChar = numStr.charAt(i);
        if (numChar != '0') {
            break;
        }
    }
    if (i == numStr.length) {
        return '0';
    }
    return numStr.substring(i);
}


/**
 * 右对齐，从 第 0 开始进行正整数加法运算
 * @param str1 待加数
 * @param str2 待加数
 * @param needAdd 开始的时候是否需要进位
 * @returns {string}
 */
function positiveStrAddInRightAlign(str1, str2, needAdd) {
    let minStr = str1;
    let maxStr = str2;
    let diff = 0;
    if (minStr.length > maxStr.length) {
        minStr = str2;
        maxStr = str1;
    }
    diff = maxStr.length - minStr.length;
    let newStr = '';
    for (let i = maxStr.length - 1; i >= 0; i--) {
        let num2 = Number.parseInt(maxStr.charAt(i));
        let num1 = 0;
        let minNumIndex = i - diff;
        if (minNumIndex >= 0) {
            num1 = Number.parseInt(minStr.charAt(minNumIndex));
        }
        let sum = num1 + num2 + needAdd;
        newStr = (sum % 10) + newStr;
        if (sum >= 10) {
            needAdd = 1;
        } else {
            needAdd = 0;
        }
    }
    if (needAdd == 1) {
        newStr = '1' + newStr;
    }
    return newStr;
}


class NumberObject {
    constructor(numStr) {
        this.value = numStr;
        var firstChar = numStr.charAt(0);
        if (isSign(firstChar)) {
            // 为正负号
            this.sign = firstChar;
            this.numStart = 1;
        } else {
            this.sign = '';
            this.numStart = 0;
        }
        // 获取小数点的位置
        var pointIndex = numStr.indexOf('.');
        this.pointStart = pointIndex;
        // 获取小数的长度
        if (pointIndex > 0) {
            this.decimalLength = numStr.length - (pointIndex + 1);
        } else {
            this.decimalLength = 0;
        }
    }

    getDecimalStr() {
        if (this.decimalLength > 0) {
            return this.value.substr(this.pointStart + 1);
        }
        return '';
    }

    getPositiveStr() {
        let tmpVal = this.value;
        if (this.decimalLength > 0) {
            return tmpVal.substring(this.numStart, this.pointStart);
        }
        return tmpVal.substr(this.numStart);
    }

    hasSign() {
        if (this.numStart > 0) {
            return true;
        }
        return false;
    }

    /**
     * 加法
     * @param num2Obj 加数
     * @returns {string}
     */
    add(num2Obj) {
        let needAdd = 0;
        let decimalStr1 = '';
        // 处理小数部分
        if (this.decimalLength > 0 && num2Obj.decimalLength > 0) {
            // 获取+开始运算的部分
            let addStartIndex = Math.min(this.decimalLength, num2Obj.decimalLength);
            let maxLength = Math.max(this.decimalLength, num2Obj.decimalLength);
            let str1 = this.getDecimalStr();
            let str2 = num2Obj.getDecimalStr();
            // 进行加法运算
            decimalStr1 = positiveStrAddInLeftAlign(str1, str2, addStartIndex - 1);
            if (decimalStr1.length > maxLength) {
                // 小数进位整数
                needAdd = 1;
                decimalStr1 = decimalStr1.substr(1);
            }
        } else if (this.decimalLength > 0) {
            decimalStr1 = this.getDecimalStr();
        } else if (num2Obj.decimalLength > 0) {
            decimalStr1 = num2Obj.getDecimalStr();
        }
        // 处理整数部分
        let positiveStr1 = this.getPositiveStr();
        let positiveStr2 = num2Obj.getPositiveStr();
        let positiveStr = positiveStrAddInRightAlign(positiveStr1, positiveStr2, needAdd);
        // 加上符号
        if (this.hasSign()) {
            positiveStr = this.sign + positiveStr;
        }

        if (decimalStr1 !== '') {
            return positiveStr + "." + decimalStr1;
        } else {
            return positiveStr;
        }
    }

    /**
     * 减法
     * @param num2Obj 减数
     */
    subtract(num2Obj) {
        let result = this.compare(num2Obj);
        let bigNumObj = this;
        let smallNumObj = num2Obj;
        if (result == 0) {
            return 0;
        } else if (result == -1) {
            bigNumObj = num2Obj;
            smallNumObj = this;
        }

        let borrow = 0;

        // 小数部分的减法
        let decimalResult = '';
        let bigDecimalStr = bigNumObj.getDecimalStr();
        let smallDecimalStr = smallNumObj.getDecimalStr();
        let maxLength = Math.max(bigDecimalStr.length, smallDecimalStr.length);
        for (let i = maxLength - 1; i >= 0; i--) {
            let bigNum = 0;
            if (i < bigDecimalStr.length) {
                bigNum = Number.parseInt(bigDecimalStr.charAt(i));
            }

            let smallNum = 0;
            if (i < smallDecimalStr.length) {
                smallNum = Number.parseInt(smallDecimalStr.charAt(i));
            }
            bigNum = bigNum - borrow;
            let result = bigNum - smallNum;
            if (result >= 0) {
                borrow = 0;
            } else {
                borrow = 1;
                result = bigNum + 10 - smallNum;
            }
            decimalResult = result + decimalResult;
        }


        // 整数部分的减法
        let bigNumPositiveStr = bigNumObj.getPositiveStr();
        let smallNumPositiveStr = smallNumObj.getPositiveStr();
        let bigNumPositivePointer = bigNumPositiveStr.length - 1;
        let smallNumPositivePointer = smallNumPositiveStr.length - 1;

        let resultStr = '';

        // 10   9
        for (; bigNumPositivePointer >= 0; smallNumPositivePointer--, bigNumPositivePointer--) {
            let smallNum = 0;
            if (smallNumPositivePointer >= 0) {
                smallNum = Number.parseInt(smallNumPositiveStr[smallNumPositivePointer]);
            }

            let bigNum = Number.parseInt(bigNumPositiveStr[bigNumPositivePointer]);
            bigNum = bigNum - borrow;
            let result = bigNum - smallNum;
            if (result >= 0) {
                borrow = 0;
            } else {
                borrow = 1;
                result = bigNum + 10 - smallNum;
            }
            resultStr = result + resultStr;
        }
        resultStr = clearZeroPrefix(resultStr);
        if (decimalResult != '') {
            resultStr = resultStr + '.' + decimalResult;
        }
        if (bigNumObj.sign == '-') {
            return '-' + resultStr;
        }

        return resultStr;
    }


    compare(num2Obj) {
        // 处理整数部分
        let positiveStr1 = this.getPositiveStr();
        let positiveStr2 = num2Obj.getPositiveStr();
        if (positiveStr1.length > positiveStr2.length) {
            return 1;
        } else if (positiveStr1.length < positiveStr2.length) {
            return -1;
        } else {
            for (let i = 0; i < positiveStr1.length; i++) {
                let num1 = Number.parseInt(positiveStr1.charAt(i));
                let num2 = Number.parseInt(positiveStr2.charAt(i));
                if (num1 > num2) {
                    return 1;
                } else if (num1 < num2) {
                    return -1;
                }
            }
        }

        // 处理小数部分
        let decimalStr1 = this.getDecimalStr();
        let decimalStr2 = num2Obj.getDecimalStr();
        let i = 0;
        for (; i < positiveStr1.length; i++) {
            let num1 = Number.parseInt(positiveStr1.charAt(i));
            let num2 = 0;
            if (i < decimalStr2.length) {
                num2 = Number.parseInt(positiveStr2.charAt(i));
            }
            if (num1 > num2) {
                return 1;
            } else if (num1 < num2) {
                return -1;
            }
        }
        for (; i < positiveStr2.length; i++) {
            let num = Number.parseInt(positiveStr2.charAt(i));
            if (num > 0) {
                return -1;
            }
        }
        return 0;
    }
}

/**
 * 判断是否为正负号
 * @param char 待判断字符
 * @returns {boolean} true-是正负号 false-非正负号
 */
function isSign(char) {
    if (char == '+' || char == '-') {
        return true;
    }
    return false;
}

/**
 * 判断是否为正数
 * @param num1Str 待判断的值
 * @returns {boolean} true-正数 false-非正数
 */
function isPositiveNum(num1Str) {
    if (isNumber(num1Str)) {
        var firstChar = num1Str.charAt(0);
        if (firstChar === '-') {
            return false;
        }
        return true;
    }
    return false;
}

/**
 * 判断是否为数字字符
 * @param charCode 待判断的值
 * @returns {boolean} true-数字字符 false-非数字字符
 */
function isDigitChar(charCode) {
    if (charCode.length > 1) {
        return false;
    }
    var oneChar = charCode.charCodeAt(0);
    if (oneChar >= 48 && oneChar <= 57) {
        // 其他的字符为数字
        return true;
    }
    return false;
}

/**
 * 判断是否为数字
 * @param num1Str 待判断的值
 * @returns {boolean} true-数字 false-非数字
 * @example
 * isNumber('100'),isNumber('+100'),isNumber('-100'),
 * isNumber('-100.0'),isNumber('-1.00.0'),isNumber('-100.a')
 */
function isNumber(num1Str) {
    var length = num1Str.length;
    if (length == 0) {
        throw new TypeError("参数非法");
    }
    var point = 0;
    for (var i = 0; i < length; i++) {
        var char = num1Str.charAt(i);
        if (i == 0 && isSign(char) && length > 1) {
            // 第一个字符为正负符号
            continue;
        }
        if (char == '.' && i != 0 && i < length - 1 && point == 0 && isDigitChar(num1Str.charAt(i - 1))) {
            point++;
            // 非第一个并且非最后一个为 .
            // . 只能出现一次
            continue;
        }
        if (isDigitChar(char)) {
            // 其他的字符为数字
            continue;
        }

        // 其他情况为 非数字
        return false;
    }
    return true;
}


/**
 * 金额转文本
 * @param amt
 */
function amtText(amt) {
    var amtStr = amt.toString();
    var pointIndex = amtStr.indexOf('.');
    var tmpAmt = amtStr;
    var change = '';
    if (pointIndex >= 0) {
        tmpAmt = amtStr.substring(0, pointIndex);
        let bit = 0;
        for (let i = pointIndex + 1; i < amtStr.length; i++) {
            var char = amtStr.charAt(i);
            var num = Number.parseInt(char);
            if (num > 0) {
                change = change + zhCn[num];
                if (bit == 0) {
                    change = change + '角'
                } else if (bit == 1) {
                    change = change + '分'
                } else {
                    throw Error('输入的数字不合法!!');
                }
            }
            bit++;
        }
    }
    var result = ''
    if (tmpAmt != '0') {
        result = number2digit(tmpAmt) + "元" + change;
    } else {
        result = change;
    }

    return result;
}

var zhTw = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖', '拾'];
var zhCn = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
var zhDa = ['零', '幺', '二', '三', '四', '五', '六', '七', '八', '九', '拾'];
var num = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
var numBaseUnit = ['十', '百', '千'];
var numHighUnit = ['万', '亿', '兆', '京', '垓', '秭'];

/**
 * 数字转中文
 * @param str 正整数
 * @returns {string}
 */
function number2Chinese(str) {
    var result = '';
    var baseUnitIndex = -1;
    var highUnitIndex = -1;
    var highUnitSet = false;
    var beforeNum = 0;
    for (var i = str.length - 1; i >= 0; i--) {

        var char = str.charAt(i);
        var num = Number.parseInt(char);

        if (baseUnitIndex > 0 && baseUnitIndex % numBaseUnit.length == 0) {
            baseUnitIndex = -1;
            highUnitIndex++;
            highUnitSet = true;
        }

        if (num != 0) {
            if (highUnitIndex >= 0 && highUnitSet) {
                result = numHighUnit[highUnitIndex % numHighUnit.length] + result;
                highUnitSet = false;
            }
            if (baseUnitIndex >= 0) {
                result = numBaseUnit[baseUnitIndex % numBaseUnit.length] + result;
            }
        }

        if (num == 0 && beforeNum == 0 && i != 0) {
            // 个位为0不做处理
        } else if (num == 1 && i == 0 && baseUnitIndex == 0) {
            // 最高位为1，并且单位为十的时候 不做处理
        } else {
            result = zhCn[num] + result;
        }
        beforeNum = num;
        baseUnitIndex++;
    }
    return result;
}

/**
 * 数字转号码
 * @param str
 * @param lang
 * @returns {*}
 */
function digit2Number(str, lang) {
    if (str != null && str != '') {
        if (lang == 'zh-cn' || lang == 'zh-ca') {
            for (var i = 0; i < num.length - 1; i++) {
                str = str.replace(new RegExp(num[i], "gm"), zhCn[i]);
            }
        } else if (lang == 'zh-tw') {
            for (var i = 0; i < num.length - 1; i++) {
                str = str.replace(new RegExp(num[i], "gm"), zhTw[i]);
            }
        } else if (lang == 'zh-da') {
            for (var i = 0; i < num.length - 1; i++) {
                str = str.replace(new RegExp(num[i], "gm"), zhDaily[i]);
            }
        }

        return str;
    }
    return '';
}

/**
 * 0和正整数
 * @param val
 * @returns {boolean}
 */
function isZeroAndPositive(val){
    var reg = /^(0|[1-9]+[0-9]*)$/;
    if(reg.test(val)){
        return true;
    }
    return false;
}
